package com.zzyl.nursing.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.zzyl.common.core.page.TableDataInfo;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.domain.FamilyMember;
import com.zzyl.nursing.domain.FamilyMemberElder;
import com.zzyl.nursing.dto.AddElderDto;
import com.zzyl.nursing.dto.QueryDeviceDataListByDayDto;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.zzyl.nursing.service.IDeviceDataService;
import com.zzyl.nursing.service.IFamilyMemberService;
import com.zzyl.nursing.service.WechatService;
import com.zzyl.nursing.vo.FamilyMemberVo;
import com.zzyl.nursing.vo.LoginVo;
import com.zzyl.nursing.vo.QueryDeviceDataListByDayVo;
import com.zzyl.nursing.vo.MemberListVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 老人家属Service业务层处理
 *
 * @author ruoyi
 * @date 2024-09-19
 */
@Slf4j
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper,FamilyMember> implements IFamilyMemberService
{
    @Autowired
    private FamilyMemberMapper familyMemberMapper;

    @Autowired
    private WechatService wechatService;

    @Autowired
    private TokenService tokenService;

    @Resource
    private IDeviceDataService deviceDataService;


    static List<String> DEFAULT_NICK_NAME = ListUtil.of(
            "生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝");

    /**
     * 小程序登录
     *
     * @param dto
     * @return
     */
    @Override
    public LoginVo login(UserLoginRequestDto dto) {

        // 1.获取openid(调用微信的接口获取) ***
        String openid = wechatService.getOpenid(dto.getCode());

        // 2.根据openid查询用户
        LambdaQueryWrapper<FamilyMember> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FamilyMember::getOpenId, openid);
        FamilyMember familyMember = getOne(queryWrapper);

        // 3.判断用户是否存在，用户不存在，就构建用户
        if (ObjectUtil.isEmpty(familyMember)) {
            /*familyMember = new FamilyMember();
            familyMember.setOpenId(openid);*/
            familyMember = FamilyMember.builder()
                    .openId(openid)
                    .build();
        }

        // 4.获取用户的手机号（调用微信的接口获取）***
        String phone = wechatService.getPhone(dto.getPhoneCode());

        // 5. 新增或修改用户
        inserOrUpdateFamilyMember(familyMember, phone);

        // 6. 把用户的信息封装到token,返回
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", familyMember.getName());
        claims.put("userId", familyMember.getId());
        String token = tokenService.createToken(claims);

        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(familyMember.getName());

        return loginVo;
    }

    @Override
    @Transactional
    public int add(AddElderDto addElderDto) {
        Long elderId = familyMemberMapper.selectElderIdByNameAndIdCard(addElderDto.getName(),addElderDto.getIdCard());
        if (elderId ==  null){
            throw new BaseException("未找到对应老人 信息");
        }


// 2. 从 token 中解析当前登录家属的 familyMemberId
        Long familyMemberId = tokenService.getFamilyMemberId(); // 关键：获取当前登录家属ID
        if (familyMemberId == null) {
            throw new BaseException("请先登录"); // 未登录时抛出异常
        }


        // Long familyMemberId;
        // if (existingMember != null) {
        //     // 家属已存在，直接使用其ID
        //     familyMemberId = existingMember.getId();
        // } else {
        //     // 家属不存在，插入新记录
        //     FamilyMember newMember = createNewFamilyMember(dto);
        //     familyMemberDao.insert(newMember);
        //     familyMemberId = newMember.getId(); // 自增主键会自动回填到对象
        // }

        FamilyMemberElder memberElder = new FamilyMemberElder();
        memberElder.setElderId(elderId);
        memberElder.setFamilyMemberId(familyMemberId);
        memberElder.setRemark(addElderDto.getRemark());

        return familyMemberMapper.add(memberElder);
    }

    @Override
    public List<FamilyMemberVo> selectAll() {
        // 1. 获取当前登录的家属用户ID
        Long familyMemberId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(familyMemberId)) {
            throw new RuntimeException("用户未登录");
        }

        // 2. 查询该家属绑定的所有老人
        return familyMemberMapper.selectByFamilyMemberId(familyMemberId);
    }

    @Override
    public List<MemberListVo> listByPage() {

            // 1. 获取当前登录的家属用户ID
            Long familyMemberId = UserThreadLocal.getUserId();
            if (ObjectUtil.isEmpty(familyMemberId)) {
                throw new RuntimeException("用户未登录");
            }

            // 2. 查询该家属绑定的所有老人详细信息（分页已在Controller中启动）
            return familyMemberMapper.selectByPage(familyMemberId);

    }

    @Override
    public int deleteElder(Long id) {
        int i = familyMemberMapper.deleteFamilyMemberById(id);
        return i;
    }

    /**
     * 新增或修改用户
     * @param familyMember
     * @param phone
     */
    private void inserOrUpdateFamilyMember(FamilyMember familyMember, String phone) {

        // 1. 判断新的手机跟数据库中保存的手机号是否一致
        if (ObjectUtil.notEqual(familyMember.getPhone(), phone)) {
            familyMember.setPhone(phone);
        }

        // 2. id是否存在，如存在，就修改
        if (ObjectUtil.isNotEmpty(familyMember.getId())) {
            updateById(familyMember);
            return;
        }

        // 3. 不存在，就新增 (拼装用户的昵称：随机字符串+手机号后4位)
        int index = (int) (Math.random() * DEFAULT_NICK_NAME.size());
        String nickName = DEFAULT_NICK_NAME.get(index) + phone.substring(phone.length() - 4);
        familyMember.setName(nickName);
        save(familyMember);

    }

    @Override
    public List<QueryDeviceDataListByDayVo> queryDeviceDataListByDay(QueryDeviceDataListByDayDto dto) {
        log.info("开始查询按天统计数据，参数: iotId={}, functionId={}, startTime={}, endTime={}",
                dto.getIotId(), dto.getFunctionId(), dto.getStartTime(), dto.getEndTime());

        // 按照新需求重新实现
        // 1. 参数校验
        if (dto.getStartTime() == null || dto.getEndTime() == null) {
            throw new BaseException("开始时间和结束时间不能为空");
        }
        if (dto.getStartTime() >= dto.getEndTime()) {
            throw new BaseException("开始时间必须小于结束时间");
        }

        // 2. 定义返回值列表
        List<QueryDeviceDataListByDayVo> resultList = new ArrayList<>();

        // 3. 转换时间戳为LocalDateTime
        ZoneId zone = ZoneId.of("Asia/Shanghai");
        LocalDateTime startDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(dto.getStartTime()), zone);
        LocalDateTime endDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(dto.getEndTime()), zone);

        // 4. 按小时遍历时间范围，生成整点时间
        LocalDateTime currentHour = startDateTime.truncatedTo(ChronoUnit.HOURS);
        LocalDateTime endHour = endDateTime.truncatedTo(ChronoUnit.HOURS);

        // 如果开始时间不是整点，则从下一个整点开始
        if (startDateTime.isAfter(currentHour)) {
            currentHour = currentHour.plusHours(1);
        }

        while (!currentHour.isAfter(endHour)) {
            QueryDeviceDataListByDayVo vo = new QueryDeviceDataListByDayVo();

            // 5. 格式化时间为 "HH:00" 格式（如 "00:00", "01:00"）
            String formattedTime = currentHour.format(TIME_FORMATTER);
            vo.setDateTime(formattedTime);

            // 6. 查询当前小时的设备数据
            LocalDateTime hourStart = currentHour;
            LocalDateTime hourEnd = currentHour.plusHours(1).minusNanos(1);

            LambdaQueryWrapper<DeviceData> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DeviceData::getIotId, dto.getIotId())
                    .eq(DeviceData::getFunctionId, dto.getFunctionId())
                    .between(DeviceData::getAlarmTime, hourStart, hourEnd);

            List<DeviceData> deviceDataList = deviceDataService.list(queryWrapper);

            // 7. 计算当前小时数据的平均值
            double hourValue = 0.0;
            if (CollUtil.isNotEmpty(deviceDataList)) {
                // 添加调试日志
                log.info("当前小时 {} 找到 {} 条数据", formattedTime, deviceDataList.size());

                double sum = deviceDataList.stream()
                        .mapToDouble(data -> {
                            try {
                                double value = Double.parseDouble(data.getDataValue());
                                log.debug("数据值: {} -> {}", data.getDataValue(), value);
                                return value;
                            } catch (NumberFormatException e) {
                                log.warn("数据值解析失败: {}", data.getDataValue());
                                return 0.0;
                            }
                        })
                        .sum();
                hourValue = Math.round(sum / deviceDataList.size() * 10.0) / 10.0; // 保留一位小数
                log.info("当前小时 {} 计算结果: sum={}, count={}, average={}",
                        formattedTime, sum, deviceDataList.size(), hourValue);
            } else {
                log.info("当前小时 {} 没有找到数据", formattedTime);
            }

            vo.setDataValue(hourValue);
            resultList.add(vo);

            // 8. 移动到下一个小时
            currentHour = currentHour.plusHours(1);
        }

        log.info("按天统计查询完成，返回 {} 条数据", resultList.size());
        if (!resultList.isEmpty()) {
            log.info("返回数据示例: {}", resultList.get(0));
        }

        return resultList;
    }



    // 时间格式化器，用于将时间戳转换为 HH:00 格式
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:00");

    // 按周统计时的日期格式化器，用于将日期转换为 MM.dd 格式
    private static final DateTimeFormatter WEEK_DAY_FORMATTER = DateTimeFormatter.ofPattern("MM.dd");

    //时间切割,切割每小时
    // 时间切割，按小时切割，确保只包含符合要求的整点
    private List<Long> getTimePoints(Long startTime, Long endTime) {
        List<Long> timePoints = new ArrayList<>();
        // 此处已在调用前做过校验，这里可作为双重保障
        if (startTime == null || endTime == null || startTime >= endTime) {
            return timePoints;
        }
        // 转换为北京时间的LocalDateTime
        ZoneId zone = ZoneId.of("Asia/Shanghai");
        LocalDateTime startLdt = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), zone);
        LocalDateTime endLdt = LocalDateTime.ofInstant(Instant.ofEpochMilli(endTime), zone);

// 处理开始时间：整点则保留，否则取 next 整点
        LocalDateTime currentLdt;
        if (startLdt.getMinute() == 0 && startLdt.getSecond() == 0 && startLdt.getNano() == 0) {
            currentLdt = startLdt;
        } else {
            currentLdt = startLdt.plusHours(1).truncatedTo(ChronoUnit.HOURS);
        }

        // 处理结束时间：截断到整点
        LocalDateTime endTruncatedLdt = endLdt.truncatedTo(ChronoUnit.HOURS);

        // 收集整点时间戳（北京时间）
        while (!currentLdt.isAfter(endTruncatedLdt)) {
            // 转换为毫秒时间戳（带时区）
            long timestamp = currentLdt.atZone(zone).toInstant().toEpochMilli();
            timePoints.add(timestamp);
            currentLdt = currentLdt.plusHours(1);
        }

        return timePoints;
    }

    @Override
    public List<QueryDeviceDataListByDayVo> queryDeviceDataListByWeek(QueryDeviceDataListByDayDto dto) {


        // 按照新需求重新实现
        // 1. 参数校验
        if (dto.getStartTime() == null || dto.getEndTime() == null) {
            throw new BaseException("开始时间和结束时间不能为空");
        }
        if (dto.getStartTime() >= dto.getEndTime()) {
            throw new BaseException("开始时间必须小于结束时间");
        }

        // 2. 定义返回值列表
        List<QueryDeviceDataListByDayVo> resultList = new ArrayList<>();

        // 3. 转换时间戳为LocalDateTime
        ZoneId zone = ZoneId.of("Asia/Shanghai");
        LocalDateTime startDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(dto.getStartTime()), zone);
        LocalDateTime endDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(dto.getEndTime()), zone);

        // 4. 按天遍历时间范围
        LocalDateTime currentDay = startDateTime.truncatedTo(ChronoUnit.DAYS);
        LocalDateTime endDay = endDateTime.truncatedTo(ChronoUnit.DAYS);

        while (!currentDay.isAfter(endDay)) {
            QueryDeviceDataListByDayVo vo = new QueryDeviceDataListByDayVo();

            // 5. 格式化日期为 "MM.dd" 格式（如 "01.15"）
            String formattedDate = currentDay.format(WEEK_DAY_FORMATTER);
            vo.setDateTime(formattedDate);

            // 6. 查询当天的设备数据
            LocalDateTime dayStart = currentDay;
            LocalDateTime dayEnd = currentDay.plusDays(1).minusNanos(1);

            // 添加详细调试日志
            System.out.println("=== 查询参数调试 ===");
            System.out.println("当前日期: " + formattedDate);
            System.out.println("dayStart: " + dayStart);
            System.out.println("dayEnd: " + dayEnd);
            System.out.println("iotId: " + dto.getIotId());
            System.out.println("functionId: " + dto.getFunctionId());

            // 先查询时间范围内的所有数据（不限制iotId和functionId）
            LambdaQueryWrapper<DeviceData> timeOnlyWrapper = new LambdaQueryWrapper<>();
            timeOnlyWrapper.between(DeviceData::getAlarmTime, dayStart, dayEnd);
            List<DeviceData> allDataInTimeRange = deviceDataService.list(timeOnlyWrapper);
            System.out.println("时间范围内所有数据条数: " + allDataInTimeRange.size());

            if (!allDataInTimeRange.isEmpty()) {
                System.out.println("时间范围内的数据示例:");
                for (int i = 0; i < Math.min(3, allDataInTimeRange.size()); i++) {
                    DeviceData sample = allDataInTimeRange.get(i);
                    System.out.println("  - iotId: " + sample.getIotId() + ", functionId: " + sample.getFunctionId() +
                            ", alarmTime: " + sample.getAlarmTime() + ", dataValue: " + sample.getDataValue());
                }
            }

            // 再查询完整条件的数据
            LambdaQueryWrapper<DeviceData> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DeviceData::getIotId, dto.getIotId())
                    .eq(DeviceData::getFunctionId, dto.getFunctionId())
                    .between(DeviceData::getAlarmTime, dayStart, dayEnd);

            List<DeviceData> deviceDataList = deviceDataService.list(queryWrapper);
            System.out.println("完整条件查询到的数据条数: " + deviceDataList.size());

            // 7. 计算当天数据的平均值
            double dayValue = 0.0;
            if (CollUtil.isNotEmpty(deviceDataList)) {
                double sum = deviceDataList.stream()
                        .mapToDouble(data -> {
                            try {
                                return Double.parseDouble(data.getDataValue());
                            } catch (NumberFormatException e) {
                                return 0.0;
                            }
                        })
                        .sum();
                dayValue = Math.round(sum / deviceDataList.size()); // 四舍五入取整
            }

            vo.setDataValue(dayValue);
            resultList.add(vo);

            // 8. 移动到下一天
            currentDay = currentDay.plusDays(1);
        }

        return resultList;
    }

}
